﻿using System;
using System.Collections.Generic;
using System.Text;
using Vortex.Wrapper;
using Vortex.Debugging;
using Vortex.Wrapper.Direct3D;

namespace Vortex.Drawing {

	/// <summary>
	/// Represents drawing context of single-context device
	/// </summary>
	public class PrimaryDrawingContext : DrawingContext {
		private bool _fullscreen;
		private bool _verticalSync;

		/// <summary>
		/// Initializes a new instance of the <see cref="PrimaryDrawingContext"/> class.
		/// </summary>
		/// <param name="windowHandle">The window handle of context.</param>
		/// <param name="width">The starting width.</param>
		/// <param name="height">The starting height.</param>
		/// <param name="fullscreen">if set to <c>true</c> if context is started fullscreen.</param>
		/// <param name="verticalSync">if set to <c>true</c> context is started with vertical sync.</param>
		public PrimaryDrawingContext(IntPtr windowHandle, int width, int height, bool fullscreen, bool verticalSync)
			: base() {
			WindowHandle = windowHandle;
			_fullscreen = fullscreen;
			_verticalSync = verticalSync;

			SetSize(width, height);
		}

		/// <summary>
		/// Called when rendering device is created
		/// </summary>
		public void OnCreateDevice() {
			Initialize();

			Canvas = new Canvas2D(this, Device.Renderer);
		}

		/// <summary>
		/// Initialized this instance.
		/// </summary>
		protected override void Initialize() {
			HResult result = Device.ApiRef.GetSwapChain(0, out _swapChain);
			Watcher.AssertCritical(result, "Retrieve primary swap chain");

			Direct3DSurface9 backbufferSurface;
			result = _swapChain.GetBackBuffer(0, out backbufferSurface);
			Watcher.AssertCritical(result, "Retrieve primary backbuffer surface");
			_backbuffer = new Surface(Device, backbufferSurface);

			result = Device.ApiRef.GetDepthStencilSurface(out _depthStencil);
			Watcher.AssertCritical(result, "Retrieve primary depth stencil surface");

			RaiseCreateSurfaceEvent();
		}

		/// <summary>
		/// Prepares the present parameters for current context.
		/// </summary>
		/// <param name="presentParameters">The present parameters.</param>
		protected internal override void PreparePresentParameters(out PresentParameters presentParameters) {
			presentParameters = new PresentParameters();
			presentParameters.EnableAutoDepthStencil = true;
			presentParameters.AutoDepthStencilFormat = D3DFormat.D16;
			presentParameters.Windowed = !_fullscreen;
			presentParameters.SwapEffect = D3DSwapEffect.Discard;
			presentParameters.BackBufferFormat = _fullscreen ? D3DFormat.X8R8G8B8 : D3DFormat.Unknown;
			presentParameters.DeviceWindow = WindowHandle;
			presentParameters.PresentationInterval = _verticalSync ? D3DPresentInterval.One : D3DPresentInterval.Immediate;
			presentParameters.BackBufferWidth = (uint)_size.Width;
			presentParameters.BackBufferHeight = (uint)_size.Height;
			presentParameters.Flags = 1;
			//presentParameters.MultiSampleType = D3DMultisampleType.x4;
			//presentParameters.MultiSampleQuality = 4;
		}

		/// <summary>
		/// Resets this drawing context.
		/// </summary>
		protected override void Reset() {
			if (!Device.TryReset()) {
				Watcher.Crush("Can't reset primary context");
			}
		}

		#region Public Interface

		/// <summary>
		/// Gets or sets a value indicating whether this <see cref="PrimaryDrawingContext"/> is fullscreen.
		/// </summary>
		/// <value><c>true</c> if fullscreen; otherwise, <c>false</c>.</value>
		public bool Fullscreen {
			get { return _fullscreen; }
			set {
				if (_fullscreen != value) {
					_fullscreen = value;
					Reset();
				}
			}
		}

		/// <summary>
		/// Gets or sets a value indicating whether vertical sync is enabled.
		/// </summary>
		/// <value><c>true</c> if vertical sync is enabled otherwise, <c>false</c>.</value>
		public bool VerticalSync {
			get { return _verticalSync; }
			set {
				if (_verticalSync != value) {
					_verticalSync = value;
					Reset();
				}
			}
		}

		/// <summary>
		/// Reconfigures the drawing context.
		/// </summary>
		/// <param name="width">The new width.</param>
		/// <param name="height">The new height.</param>
		/// <param name="fullscreen">Fullscreen state</param>
		/// <param name="verticalSync">Vertical sync state</param>
		public void Reconfigure(int width, int height, bool fullscreen, bool verticalSync) {
			System.Drawing.Size oldSize = _size;
			
			SetSize(width, height);
			_fullscreen = fullscreen;
			_verticalSync = verticalSync;
			
			//reset context after parameters are updated
			Reset();

			//check invoke event
			if (oldSize != _size ) {
				InvokeSurfaceResizeEvent();
			}
		}

		#endregion

	}

}
